<template>
  <div class="wps-pdf">
    <wps-edit-bar />
    <div class="pdf-view">
      <div v-if="!pdfLoaded" class="loading">
        <loading />
      </div>
      <div class="thumbnail" v-show="pdfLoaded">
        <div class="name">缩略图</div>
        <ul class="thumbnail-list" ref="thumbnailListDom" @wheel="handlePdfWheel" @scroll="handlePdfWheel">
          <li
            v-for="(item, index) in pdfList"
            :key="item.id"
            :class="{ checked: currentIndex === index }"
            @click.stop="handleScrollView(index)"
          >
            <canvas :data-id="item.id" />
            <span>第{{ index + 1 }}页</span>
          </li>
        </ul>
      </div>
      <div v-show="pdfLoaded" class="pdf" ref="pdfViewDom" @wheel="handlePdfWheel" @scroll="handlePdfWheel">
        <canvas
          v-for="item in pdfList"
          :key="item.id"
          :data-id="item.id"
          :style="{ width: `${item.width}px`, height: `${item.height}px` }"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import WpsEditBar from '@/components/systemWindow/wps/wpsEditBar.vue'
import { nextTick, ref, watch } from 'vue'
import { randomWord } from '@/utils/utils'
import { GlobalWorkerOptions, getDocument } from 'pdfjs-dist'
import type { PropType } from 'vue'

const props = defineProps({
  data: {
    type: String as PropType<string>,
    required: true
  }
})

let pageData: any
const pdfViewDom = ref<HTMLElement>()
const thumbnailListDom = ref<HTMLElement>()
const pdfLoaded = ref<boolean>(false)
const totalPage = ref<number>(0)
const currentIndex = ref<number>(0)
const currentPage = ref<number>(5)
const pdfList = ref<{ id: string; width: number; height: number; isRender: boolean }[]>([])

// 初始化
const init = async () => {
  pdfLoaded.value = false
  // @ts-ignore
  GlobalWorkerOptions.workerSrc = await import('pdfjs-dist/legacy/build/pdf.worker.entry.js')
  pageData = await getDocument(props.data).promise
  pdfList.value = Array.from(new Array(pageData.numPages)).map(() => ({
    id: randomWord(20, 'wps-pdf-'),
    width: 0,
    height: 0,
    isRender: false
  }))
  await nextTick()
  totalPage.value = pageData.numPages
  if (currentPage.value > totalPage.value) currentPage.value = totalPage.value
  pdfViewDom.value?.scrollTo(0, 0)
  for (let i = 0; i < currentPage.value; i++) {
    renderPdf(pdfList.value[i].id, i)
  }
  pdfLoaded.value = true
}

// 渲染PDF
const renderPdf = async (id: string, num: number) => {
  const canvasDomList = Array.from(document.querySelectorAll(`canvas[data-id="${id}"]`)) as HTMLCanvasElement[]
  if (!canvasDomList.length) return
  pdfList.value[num].isRender = true
  for (let i = 0; i < canvasDomList.length; i++) {
    const item = canvasDomList[i]
    const ctx = item.getContext('2d') as CanvasRenderingContext2D
    const dpr = window.devicePixelRatio || 1
    const bsr = 1
    const ratio = dpr / bsr
    const page = await pageData.getPage(num + 1)
    const viewport = page.getViewport({ scale: 1 })
    item.width = viewport.width * ratio
    item.height = viewport.height * ratio
    if (!pdfList.value[0].width) {
      pdfList.value.forEach((item) => {
        item.width = viewport.width * ratio
        item.height = viewport.height * ratio
      })
    }
    pageData.pdfWidth = viewport.width + 'px'
    ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
    const renderContext = {
      canvasContext: ctx,
      viewport: viewport
    }
    page.render(renderContext)
  }
}

// 监听滚轮事件
const handlePdfWheel = (ev: WheelEvent | Event) => {
  const target = ev.currentTarget as HTMLElement
  const children = Array.from(target.children) as HTMLCanvasElement[]
  currentPage.value = children.findIndex((item, index) => {
    return item.offsetTop <= target.scrollTop * 5 && index > currentPage.value
  })
  if (/pdf/.test(target.className)) {
    let index = children.findIndex((item) => item.offsetTop + target.offsetHeight / 2 >= target.scrollTop)
    index = target.scrollTop > 0 && index === -1 ? children.length - 1 : index
    currentIndex.value = target.scrollTop === target.scrollHeight - target.offsetHeight ? children.length - 1 : index
    handleScrollView(index, thumbnailListDom.value)
  }
}

// 滚动到指定位置事件
const handleScrollView = (index: number, dom?: HTMLElement) => {
  dom = dom || pdfViewDom.value
  if (!dom) return
  const children = Array.from(dom.children) as HTMLCanvasElement[]
  dom?.scrollTo(0, children[index]?.offsetTop - dom?.offsetTop)
}

watch(currentPage, (val, old) => {
  if (val > old && !pdfList.value[val].isRender) renderPdf(pdfList.value[val].id, val)
})

watch(() => props.data, init, { immediate: true, deep: true })
</script>

<style scoped lang="scss">
@import '@/assets/scss/mixin';

.wps-pdf {
  .pdf-view {
    width: 100%;
    height: calc(100% - 26px - 78px - 6px * 2);
    display: flex;
    align-items: center;
    justify-content: space-between;

    .loading {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
    }

    .thumbnail {
      display: flex;
      flex-direction: column;
      align-items: center;
      flex: 1;
      height: calc(100% - 60px);

      .name {
        height: 40px;
        line-height: 40px;
        font-size: 14px;
      }

      .thumbnail-list {
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 100%;
        height: calc(100% - 40px);
        overflow-y: auto;
        @include scroll-bar;

        li {
          width: 180px;
          margin-bottom: 20px;
          display: inline-flex;
          flex-direction: column;
          align-items: center;
          border-radius: 6px;
          padding: 15px 0;
          background-color: rgb(216, 223, 223);

          &.checked {
            canvas {
              border-color: #f00;
            }
          }

          canvas {
            border-radius: 6px;
            width: 160px;
            height: 230px;
            margin-bottom: 20px;
            border: 1px solid transparent;
          }
        }
      }
    }

    .pdf {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 20px;
      box-sizing: border-box;
      flex: 3;
      margin: 10px 30px 30px;
      height: calc(100% - 40px);
      overflow-y: auto;
      @include scroll-bar;
    }
  }
}
</style>
